package com.bike.bikeserver.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bike.bikeserver.common.core.domain.CommonResult;
import com.bike.bikeserver.common.enums.ModelResultLongEnums;
import com.bike.bikeserver.common.enums.ModelTypeEnums;
import com.bike.bikeserver.common.utils.HttpUtils;
import com.bike.bikeserver.common.utils.ModelUtils;
import com.bike.bikeserver.common.utils.StringUtils;
import com.bike.bikeserver.domain.Model;
import com.bike.bikeserver.domain.ModelTestLog;
import com.bike.bikeserver.domain.vo.ModelTestImgVo;
import com.bike.bikeserver.mapper.ModelMapper;
import com.bike.bikeserver.mapper.ModelTestLogMapper;
import com.bike.bikeserver.service.IModelService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author ZZX
 * @since 2023-08-07
 */
@Service
@Slf4j
public class ModelServiceImpl extends ServiceImpl<ModelMapper, Model> implements IModelService
{
    @Autowired
    ModelMapper modelMapper;
    @Autowired
    ModelTestLogMapper modelTestLogMapper;


    @Override
    public CommonResult getModelList()
    {
        List<Model> models = modelMapper.selectList(null);
        return CommonResult.success(models);
    }

    @Override
    public CommonResult getModelLikeSth(String sth, String info)
    {
        if (sth == null || StringUtils.isBlank(sth))
        {
            return CommonResult.warn("请勿提交空值！");
        }
        LambdaQueryWrapper<Model> wrapper = new LambdaQueryWrapper<>();
        if ("模型名称".equals(sth))
        {
            wrapper.like(Model::getModelName, info);
        }
        else
        {
            wrapper.like(Model::getModelType, info);
        }
        List<Model> models = modelMapper.selectList(wrapper);
        return CommonResult.success("查询成功！为您找到" + models.size() + "条记录！", models);
    }

    @Override
    public CommonResult testModel(ModelTestImgVo modelTestImgVo)
    {
        try
        {
            // 获取模型测试api
            Model model = modelMapper.selectById(modelTestImgVo.getModelId());
            String modelTestApi = model.getModelApi();
            // 根据模型类型设置不同的参数，调用不同的模型方法
            JSONObject params = new JSONObject();
            String responseBody = "";
            if (!(modelTestImgVo == null || modelTestImgVo.getImageCodes() == null || modelTestImgVo.getImageCodes().length == 0))
            {
                String[] zips = zipImageCodes(Arrays.asList(modelTestImgVo.getImageCodes()));
                modelTestImgVo.setImageCodes(zips);
            }
            if (ModelTypeEnums.SYNTHESIS.getValue().equals(model.getModelType()))
            {
                if (modelTestImgVo.getImageCodes().length > 1)
                {
                    return CommonResult.warn(ModelTypeEnums.SYNTHESIS.getValue() + "接口只支持单张图片测试！");
                }
                params.put("imageCode", modelTestImgVo.getImageCodes()[0]);
                String blendDetectImg = ModelUtils.getBlendDetectImg(modelTestApi, params);
                JSONObject imageObject = new JSONObject();
                imageObject.put("detections", new JSONArray());
                imageObject.put("image_base64", blendDetectImg);
                imageObject.put("image_name", "blend.jpg");

                JSONArray detailsArray = new JSONArray();
                detailsArray.add(imageObject);

                JSONArray logsArray = new JSONArray();
                logsArray.add(":绿色区域表示单车停放区域，综合识别训练时间：" + new SimpleDateFormat("yyyy-MM-dd HH：mm：ss").format(new Date()));

                JSONObject jsonObject = new JSONObject();
                jsonObject.put("details", detailsArray);
                jsonObject.put("logs", logsArray);

                responseBody = jsonObject.toJSONString();
            }
            else if (ModelTypeEnums.YOLO.getValue().equals(model.getModelType()) || ModelTypeEnums.DEEPLAB.getValue().equals(model.getModelType()))
            {
                params.put("imageCodes", modelTestImgVo.getImageCodes());
                // 发送请求
                log.info("请求地址为：" + modelTestApi);
                ResponseEntity<String> response = HttpUtils.sendPostV2(modelTestApi, params);
                responseBody = response.getBody();
                JSONObject jsonObject = JSONObject.parseObject(responseBody);
                String resLogs = jsonObject.getString("logs");
                log.info("请求地址为：" + modelTestApi + "，返回日志结果为：" + resLogs);
            }
            else if (ModelTypeEnums.PARKING.getValue().equals(model.getModelType()))
            {
                if (modelTestImgVo.getImageCodes().length > 1)
                {
                    return CommonResult.warn(ModelTypeEnums.SYNTHESIS.getValue() + "接口只支持单张图片测试！");
                }
                params.put("imageCode", modelTestImgVo.getImageCodes()[0]);
                String resTxt = ModelUtils.getDeepLabV3Result(modelTestApi, params);
                JSONObject imageObject = new JSONObject();
                imageObject.put("detections", new JSONArray());
                imageObject.put("image_base64", ModelResultLongEnums.IMAGE_BEHIND.getValue());
                imageObject.put("image_name", "parking.png");

                JSONArray detailsArray = new JSONArray();
                detailsArray.add(imageObject);

                JSONArray logsArray = new JSONArray();
                logsArray.add(resTxt);

                JSONObject jsonObject = new JSONObject();
                jsonObject.put("details", detailsArray);
                jsonObject.put("logs", logsArray);

                responseBody = jsonObject.toJSONString();
            }
            else if (ModelTypeEnums.LSTM.getValue().equals(model.getModelType()))
            {
                List<Integer> periodFlow = new ArrayList<>();
                periodFlow.add(modelTestImgVo.getZoneTemp());
                periodFlow.add(modelTestImgVo.getZoneWeather());
                periodFlow.add(modelTestImgVo.getZonePower());
                periodFlow.add(modelTestImgVo.getIsHoliday());
                periodFlow.add(modelTestImgVo.getIsWeekend());
                periodFlow.add(modelTestImgVo.getNearbyZoneNum());
                periodFlow.add(modelTestImgVo.getK1ZoneFlow());
                periodFlow.add(modelTestImgVo.getK2ZoneFlow());
                periodFlow.add(modelTestImgVo.getK3ZoneFlow());
                List<List<Integer>> finalPeriodFlow = new ArrayList<>();
                finalPeriodFlow.add(periodFlow);
                params.put("period_flow", finalPeriodFlow);
                String lstmResult = ModelUtils.getLstmResult(modelTestApi, params);
                JSONObject imageObject = new JSONObject();
                imageObject.put("detections", new JSONArray());
                imageObject.put("image_base64", ModelResultLongEnums.IMAGE_BEHIND.getValue());
                imageObject.put("image_name", "flow.png");

                JSONArray detailsArray = new JSONArray();
                detailsArray.add(imageObject);

                JSONArray logsArray = new JSONArray();
                logsArray.add(lstmResult);

                JSONObject jsonObject = new JSONObject();
                jsonObject.put("details", detailsArray);
                jsonObject.put("logs", logsArray);

                responseBody = jsonObject.toJSONString();

            }

            // 保存入库
            ModelTestLog testLog = new ModelTestLog();
            testLog.setModelId(model.getId());
            testLog.setModelName(model.getModelName());
            testLog.setModelTestText(modelTestImgVo.getModelTestText());
            testLog.setModelParams(JSON.toJSONString(modelTestImgVo.getImageCodes()));
            if (ModelTypeEnums.LSTM.getValue().equals(model.getModelType()))
            {
                List<String> lstmImage = new ArrayList<>();
                lstmImage.add(ModelResultLongEnums.IMAGE_BEFORE.getValue());
                testLog.setModelParams(JSON.toJSONString(lstmImage));
            }
            testLog.setModelRes(responseBody);
            testLog.setModelTester(modelTestImgVo.getModelTester());
            modelTestLogMapper.insert(testLog);

            return CommonResult.success("测试成功", responseBody);
        }
        catch (Exception e)
        {
            e.printStackTrace();
            return CommonResult.warn("测试异常，请联系管理员处理");
        }
    }

    private static String[] zipImageCodes(List<String> imageCodes)
    {
        String[] zips = new String[imageCodes.size()];
        for (int i = 0; i < imageCodes.size(); i++)
        {
            // 压缩图片
            // 获取图片编码（包含前缀）
            String imageCodesWithPrefix = imageCodes.get(i);
            // 去掉前缀
            String base64Image = imageCodesWithPrefix.replace("data:image/png;base64,", "");
//            System.out.println("压缩前的图片编码：");
//            System.out.println(base64Image);
            // 解码Base64编码的图片
            byte[] imageBytes = Base64.getDecoder().decode(base64Image);
            // 压缩图片到原始大小的30%
            byte[] compressedImageBytes = compressImage(imageBytes, 0.5);
            // 获取压缩后的Base64编码
            String compressedImageCodes = Base64.getEncoder().encodeToString(compressedImageBytes);
//            System.out.println("压缩后的图片编码：");
//            System.out.println(compressedImageCodes);
            zips[i] = "data:image/png;base64," + compressedImageCodes;
        }
        return zips;
    }

    private static byte[] compressImage(byte[] originalImageBytes, double compressionRatio)
    {
        try
        {
            // 将原始图片字节数组转换为 BufferedImage
            ByteArrayInputStream originalImageStream = new ByteArrayInputStream(originalImageBytes);
            BufferedImage originalImage = ImageIO.read(originalImageStream);

            // 获取原始图片的宽度和高度
            int originalWidth = originalImage.getWidth();
            int originalHeight = originalImage.getHeight();

            // 计算压缩后的宽度和高度
            int compressedWidth = (int) (originalWidth * compressionRatio);
            int compressedHeight = (int) (originalHeight * compressionRatio);

            // 创建压缩后的 BufferedImage
            BufferedImage compressedImage = new BufferedImage(compressedWidth, compressedHeight, BufferedImage.TYPE_INT_RGB);

            // 绘制压缩后的图片
            compressedImage.getGraphics().drawImage(originalImage.getScaledInstance(compressedWidth, compressedHeight, BufferedImage.SCALE_SMOOTH), 0, 0, null);

            // 将压缩后的图片转换为字节数组
            ByteArrayOutputStream compressedImageStream = new ByteArrayOutputStream();
            ImageIO.write(compressedImage, "png", compressedImageStream);
            return compressedImageStream.toByteArray();

        }
        catch (IOException e)
        {
            e.printStackTrace();
            return null;
        }
    }
}
